package com.agent.gateway.handler;

import com.agent.common.result.ResultCode;
import com.agent.common.exception.AuthenticationException;
import com.agent.common.exception.BusinessException;
import com.agent.common.result.ApiResponse;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/**
 * 全局异常处理器
 *
 * @author Jeff_Wan
 * @description 统一处理网关中的异常
 */
@Order(-1)
@Component
public class GlobalExceptionHandler implements ErrorWebExceptionHandler {

    private final ObjectMapper objectMapper;

    public GlobalExceptionHandler(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        DataBufferFactory bufferFactory = exchange.getResponse().bufferFactory();

        ApiResponse<?> response;
        HttpStatus status;

        if (ex instanceof AuthenticationException) {
            status = HttpStatus.UNAUTHORIZED;
            response = ApiResponse.fail(((AuthenticationException) ex).getResultCode(), ex.getMessage());
        } else if (ex instanceof BusinessException) {
            status = HttpStatus.BAD_REQUEST;
            response = ApiResponse.fail(((BusinessException) ex).getResultCode(), ex.getMessage());
        } else {
            status = HttpStatus.INTERNAL_SERVER_ERROR;
            response = ApiResponse.fail(ResultCode.INTERNAL_SERVER_ERROR, ex.getMessage());
        }

        exchange.getResponse().setStatusCode(status);
        exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);

        try {
            String json = objectMapper.writeValueAsString(response);
            DataBuffer dataBuffer = bufferFactory.wrap(json.getBytes(StandardCharsets.UTF_8));
            return exchange.getResponse().writeWith(Mono.just(dataBuffer));
        } catch (JsonProcessingException e) {
            return Mono.error(e);
        }
    }
}